"""
HTTP客户端组件
负责处理HTTP请求和响应
"""
from typing import Dict, Any, Optional, Union, List
import json
import logging
import requests
from requests import Response, Session
from requests.exceptions import RequestException, Timeout, ConnectionError as ReqConnectionError

# 设置日志
logger = logging.getLogger("connllm.http")

class HTTPClient:
	"""HTTP客户端，负责处理HTTP请求"""
	
	def __init__(self, base_url: Optional[str] = None, 
				 headers: Optional[Dict[str, str]] = None,
				 timeout: int = 60,
				 proxy: Optional[str] = None):
		"""
		初始化HTTP客户端
		
		Args:
			base_url: 基础URL
			headers: HTTP头
			timeout: 超时时间(秒)
			proxy: 代理设置
		"""
		self.base_url = base_url
		self.headers = headers or {}
		self.timeout = timeout
		self.proxy = proxy
		
	def _get_session(self) -> Session:
		"""
		获取会话实例
		
		Returns:
			Session实例
		"""
		session = requests.Session()
		
		# 设置代理
		if self.proxy:
			session.proxies = {
				'http': self.proxy,
				'https': self.proxy
			}
			logger.debug(f"使用代理: {self.proxy}")
			
		return session
	
	def _build_url(self, endpoint: str) -> str:
		"""
		构建完整URL
		
		Args:
			endpoint: 接口路径
			
		Returns:
			完整URL
		"""
		# 如果是完整URL，直接返回
		if endpoint.startswith(('http://', 'https://')):
			return endpoint
			
		if not self.base_url:
			return endpoint
			
		# 确保base_url和endpoint之间只有一个/
		if self.base_url.endswith('/') and endpoint.startswith('/'):
			endpoint = endpoint[1:]
		elif not self.base_url.endswith('/') and not endpoint.startswith('/'):
			endpoint = '/' + endpoint
			
		return self.base_url + endpoint
	
	def request(self, method: str, endpoint: str, 
				data: Any = None, 
				params: Optional[Dict[str, Any]] = None,
				headers: Optional[Dict[str, str]] = None,
				stream: bool = False) -> Response:
		"""
		发送HTTP请求
		
		Args:
			method: HTTP方法(GET, POST等)
			endpoint: 接口路径
			data: 请求数据
			params: URL参数
			headers: 自定义头
			stream: 是否流式响应
			
		Returns:
			HTTP响应
			
		Raises:
			RequestException: 请求异常
		"""
		url = self._build_url(endpoint)
		merged_headers = {**self.headers}
		
		# 添加自定义头
		if headers:
			merged_headers.update(headers)
			
		session = self._get_session()
		
		# 记录请求信息（但排除敏感信息）
		safe_headers = self._get_safe_headers(merged_headers)
		safe_data = self._get_safe_data(data)
		logger.debug(
			f"发送请求: {method} {url}\n"
			f"头信息: {safe_headers}\n"
			f"参数: {params}\n"
			f"数据: {safe_data}"
		)
		
		start_time = __import__('time').time()
		
		try:
			json_data = None
			if data is not None and method.upper() in ('POST', 'PUT', 'PATCH'):
				if isinstance(data, (dict, list)):
					json_data = data
				elif isinstance(data, str):
					try:
						# 尝试解析字符串为JSON对象
						json_data = json.loads(data)
					except json.JSONDecodeError:
						# 如果不是有效的JSON，则作为表单数据传递
						pass
				
			response = session.request(
				method=method,
				url=url,
				json=json_data,
				data=None if json_data else data,
				params=params,
				headers=merged_headers,
				timeout=self.timeout,
				stream=stream
			)
			
			# 计算请求时间
			elapsed = __import__('time').time() - start_time
			logger.debug(f"请求完成: {method} {url}, 状态码: {response.status_code}, 耗时: {elapsed:.2f}秒")
			
			# 检查响应状态
			response.raise_for_status()
			
			return response
			
		except Timeout as e:
			elapsed = __import__('time').time() - start_time
			logger.error(f"请求超时: {method} {url}, 耗时: {elapsed:.2f}秒, 错误: {str(e)}")
			# 将请求库异常转换为标准异常，以便上层处理
			from ..core.exceptions import TimeoutError
			raise TimeoutError(f"请求超时: {str(e)}", url=url, method=method)
			
		except ReqConnectionError as e:
			elapsed = __import__('time').time() - start_time
			logger.error(f"连接错误: {method} {url}, 耗时: {elapsed:.2f}秒, 错误: {str(e)}")
			# 将请求库异常转换为标准异常，以便上层处理
			from ..core.exceptions import ConnectionError
			raise ConnectionError(f"连接错误: {str(e)}", url=url, method=method)
			
		except RequestException as e:
			elapsed = __import__('time').time() - start_time
			logger.error(f"请求错误: {method} {url}, 耗时: {elapsed:.2f}秒, 错误: {str(e)}")
			
			if hasattr(e, 'response') and e.response:
				# 尝试解析错误响应
				self._handle_error_response(e.response, url, method)
			
			# 将请求库异常转换为标准异常，以便上层处理
			from ..core.exceptions import ProviderError
			raise ProviderError(f"请求错误: {str(e)}", url=url, method=method)
	
	def _handle_error_response(self, response: Response, url: str, method: str) -> None:
		"""
		处理错误响应
		
		Args:
			response: 错误响应
			url: 请求URL
			method: 请求方法
			
		Raises:
			LLMException: 转换后的异常
		"""
		status_code = response.status_code
		
		try:
			error_data = response.json()
		except (json.JSONDecodeError, ValueError):
			error_data = {"error": response.text}
		
		# 记录错误细节
		logger.error(
			f"请求失败: {method} {url}, 状态码: {status_code}\n"
			f"错误详情: {error_data}"
		)
		
		# 根据状态码抛出不同类型的异常
		from ..core.exceptions import (
			AuthenticationError, InvalidRequestError, 
			RateLimitError, ServerError
		)
		
		if status_code == 401:
			raise AuthenticationError(
				f"身份验证失败: {error_data.get('error', '未知错误')}",
				url=url,
				method=method
			)
		elif status_code == 400:
			raise InvalidRequestError(
				f"请求无效: {error_data.get('error', '未知错误')}",
				url=url,
				method=method
			)
		elif status_code == 429:
			raise RateLimitError(
				f"请求频率超限: {error_data.get('error', '未知错误')}",
				url=url,
				method=method
			)
		elif status_code >= 500:
			raise ServerError(
				f"服务器错误: {error_data.get('error', '未知错误')}",
				url=url,
				method=method
			)
	
	def _get_safe_headers(self, headers: Dict[str, str]) -> Dict[str, str]:
		"""
		获取用于日志记录的安全头信息(移除敏感信息)
		
		Args:
			headers: 原始头信息
			
		Returns:
			安全的头信息
		"""
		sensitive_keys = ['authorization', 'x-api-key', 'api-key', 'apikey', 'token']
		safe_headers = {}
		
		for key, value in headers.items():
			if key.lower() in sensitive_keys:
				safe_headers[key] = '[REDACTED]'
			else:
				safe_headers[key] = value
				
		return safe_headers
		
	def _get_safe_data(self, data: Any) -> Any:
		"""
		获取用于日志记录的安全数据(移除敏感信息)
		
		Args:
			data: 原始数据
			
		Returns:
			安全的数据
		"""
		# 只有当数据是字典才处理
		if not isinstance(data, dict):
			return data
			
		sensitive_keys = ['api_key', 'apiKey', 'key', 'token', 'password', 'secret']
		
		# 深拷贝防止修改原始数据
		import copy
		safe_data = copy.deepcopy(data)
		
		def _redact_sensitive(obj: Union[Dict, List, Any]) -> Union[Dict, List, Any]:
			"""递归处理嵌套数据"""
			if isinstance(obj, dict):
				for key in list(obj.keys()):
					if any(sk in key.lower() for sk in sensitive_keys):
						obj[key] = '[REDACTED]'
					else:
						obj[key] = _redact_sensitive(obj[key])
			elif isinstance(obj, list):
				obj = [_redact_sensitive(item) for item in obj]
			return obj
			
		return _redact_sensitive(safe_data)
		
	def stream(self, method: str, endpoint: str, 
			  data: Any = None, 
			  params: Optional[Dict[str, Any]] = None,
			  headers: Optional[Dict[str, str]] = None) -> Response:
		"""
		发送流式HTTP请求
		
		Args:
			method: HTTP方法(GET, POST等)
			endpoint: 接口路径
			data: 请求数据
			params: URL参数
			headers: 自定义头
			
		Returns:
			HTTP响应流
			
		Raises:
			RequestException: 请求异常
		"""
		return self.request(
			method=method,
			endpoint=endpoint,
			data=data,
			params=params,
			headers=headers,
			stream=True
		)
		
	def get_json(self, endpoint: str, 
				params: Optional[Dict[str, Any]] = None,
				headers: Optional[Dict[str, str]] = None) -> Any:
		"""
		发送GET请求并返回JSON响应
		
		Args:
			endpoint: 接口路径
			params: URL参数
			headers: 自定义头
			
		Returns:
			解析后的JSON数据
			
		Raises:
			RequestException: 请求异常
			ValueError: JSON解析错误
		"""
		response = self.request('GET', endpoint, params=params, headers=headers)
		return response.json()
		
	def post_json(self, endpoint: str, 
				 data: Any,
				 params: Optional[Dict[str, Any]] = None,
				 headers: Optional[Dict[str, str]] = None) -> Any:
		"""
		发送POST请求并返回JSON响应
		
		Args:
			endpoint: 接口路径
			data: 请求数据
			params: URL参数
			headers: 自定义头
			
		Returns:
			解析后的JSON数据
			
		Raises:
			RequestException: 请求异常
			ValueError: JSON解析错误
		"""
		response = self.request('POST', endpoint, data=data, params=params, headers=headers)
		return response.json()
